package com.house.framework.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.house.exception.MyException;
import com.house.framework.constant.UserConstant;
import com.house.framework.dto.LoginDto;
import com.house.framework.entity.Logininfo;
import com.house.framework.entity.User;
import com.house.framework.entity.WxUser;
import com.house.framework.mapper.LogininfoMapper;
import com.house.framework.mapper.UserMapper;
import com.house.framework.mapper.WxUserMapper;
import com.house.framework.service.ILoginService;
import com.house.framework.utils.AjaxResult;
import com.house.utils.HttpClientUtils;
import com.house.utils.MD5Utils;
import com.house.utils.StrUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName LoginServiceImpl
 * @Version 1.0
 */
@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private UserMapper userMapper;

    @Override
    public Map<String, Object> account(LoginDto loginDto) {

        // 1.校验
        // 非空校验
        if (StringUtils.isEmpty(loginDto.getUsername()) || StringUtils.isEmpty(loginDto.getPassword())) {
            throw new MyException("参数不能为空...");
        }
        // 根据用户和类型查询t_logininfo是否存在
        Logininfo logininfo = logininfoMapper.findByUsernameAndType(loginDto);
        // 查不到直接提示用户不存在
        if (logininfo == null) {
            throw new MyException("用户不存在...");
        }
        // 查的到，判断密码是否一致，不一致提示，密码错误
        String dbPwd = logininfo.getPassword();
        String salt = logininfo.getSalt();
        String byMd5 = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        if (!dbPwd.equals(byMd5)) {
            throw new MyException("密码错误...");
        }
        // 正确，把信息存入redis
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 1, TimeUnit.HOURS);
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        // 不能让前端看见用户信息
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        map.put("logininfo", logininfo);
        Long id = logininfo.getId();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        User user = userMapper.selectOne(wrapper.lambda().eq(User::getLogininfo_id, id));
//        user.setSalt(null);
//        user.setPassword(null);
        map.put("user", user);
        return map;
    }


    /**
     * @Description wechat登录流程
     * @Param
     * @Return
     */
    @Override
    public AjaxResult wechat(Map<String, String> params) {
        String code = params.get("code");
        // 判断code是否为空
        if (!StringUtils.hasLength(code)) { // 认为是空，返回true
            throw new MyException("授权码不存在");
        }

        //  通过code获取token（令牌）  获取的是json格式的字符串
        String strObj = HttpClientUtils.httpGet(UserConstant.TOKEN_BY_CODE
                .replace("APPID", UserConstant.APPID)
                .replace("SECRET", UserConstant.SECRET)
                .replace("CODE", code));

        // 把json格式的字符串转成json对象
        JSONObject jsonObject = JSONObject.parseObject(strObj);
        // 获取到token  令牌
        String accessToken = jsonObject.getString("access_token");
        // 获取到openId
        String openId = jsonObject.getString("openid");

        // 根据openId查询wxUser表
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        // 判断wxUser是否为空，如果不为空，并且user_id存在 免密登录
        if (wxUser != null && wxUser.getUser_id() != null) {  // 免密登录
            // 登录成功  向redis中logininfo保存信息。
            // 通过user_id 查询logininfo
            Logininfo logininfo = logininfoMapper.findByUserId(wxUser.getUser_id());

            // 如果没有问题，把用户信息存入redis中
            String token = UUID.randomUUID().toString();
            //  对象存储到redis，需要序列化
            redisTemplate.opsForValue().set(token,
                    logininfo,
                    30,
                    TimeUnit.MINUTES);

            Map<String, Object> map = new HashMap<>();
            // map中应该存token， 用户信息
            map.put("token", token);

            //  不能让前端看到用户机密信息
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo", logininfo);

            return AjaxResult.me().setResultObj(map);

        } else { // 当前没有扫描过
            // 返回token和openid，给前端
            String param = "?accessToken=" + accessToken + "&openId=" + openId;
            return AjaxResult.me().setSuccess(false).setResultObj(param);
        }
    }

    /**
     * @Description 微信绑定
     * @Param
     * @Return
     */
    @Override
    public Map<String, Object> binder(Map<String, String> param) {
        // 校验
        // 参数不为空
        String phone = param.get("Phone");
        String verifyCode = param.get("verifyCode");
        String accessToken = param.get("accessToken");
        String openId = param.get("openId");
        if (!StringUtils.hasLength(phone)
                || !StringUtils.hasLength(verifyCode)
                || !StringUtils.hasLength(accessToken)
                || !StringUtils.hasLength(openId)) {
            throw new MyException("参数不能为空...");
        }

        // 验证码是否过期
        // 4.验证码校验
        Object obj = redisTemplate.opsForValue().get(UserConstant.BINDER_PREFIX + phone);
        if (obj == null) {
            throw new MyException("验证码过期，请重新获取");
        } else {
            // 取出验证码，不区分大小写验证
            String redisCode = obj.toString().split(":")[1];
            if (!redisCode.equalsIgnoreCase(verifyCode)) {
                throw new MyException("验证码错误，请重新输入");
            }
        }
            // 手机是否注册
            User tmpuser = userMapper.findByPhone(phone);
            User user = null;
            Logininfo logininfo = null;
            if (tmpuser != null) {
                // 直接绑定
                user = tmpuser;
                // 根据logininfo_id查询logininfo
                logininfo = logininfoMapper.findByUserId(user.getId());
            } else {
                // 生成t_user, t_logininfo, t_wxuser
                user = initUser(phone);
                logininfo = initLogininfo(user);

                // 先保存logininfo 返回自增主键
                logininfoMapper.add(logininfo);
                user.setLogininfo_id(logininfo.getId());
                userMapper.add(user);
            }

            // 获取wxuser
            String wxuser = UserConstant.WX_USER
                    .replace("ACCESS_TOKEN", accessToken)
                    .replace("OPENID", openId);
            // 发送请求
            String strObj = HttpClientUtils.httpGet(wxuser); // 发送请求
            WxUser wxUser = initWxUser(strObj, user); // 绑定
            wxUserMapper.add(wxUser); // 添加微信用户

            // 正确，把信息存入redis
            String token = UUID.randomUUID().toString();
            //  对象存储到redis，需要序列化
            redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            // 不能让前端看见用户信息
            logininfo.setPassword(null);
            logininfo.setSalt(null);
            map.put("logininfo", logininfo);
            return map;

        }
    
    /**
     *@Description 获取wxuser
     *@Param
     *@Return
     */
    private WxUser initWxUser(String strObj, User user) {
        JSONObject jsonObject = JSONObject.parseObject(strObj);
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        wxUser.setUser_id(user.getId());
        return wxUser;
    }

    /**
     *@Description 根据user获取logininfo
     *@Param
     *@Return 
     */
    private Logininfo initLogininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        logininfo.setDisable(1);
        return logininfo;
    }

    /**
     * @Description 通过手机号获取user
     * @Param
     * @Return
     */
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        user.setState(1);
        // 盐值随机生成
        String salt = StrUtils.getComplexRandomString(32);
        // 密码：加密加盐
        String password = MD5Utils.encrypByMd5(1 + salt);
        user.setSalt(salt);
        user.setPassword(password);
        return user;
    }
}
